package com.zdp.filesync.commonline.service.impl;

import com.zdp.filesync.commonline.entity.StreamGobbler;
import com.zdp.filesync.commonline.service.CommonLine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.*;
import java.util.function.Function;

@Slf4j
public abstract class AbstractCommonLine implements CommonLine {

    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 20, 10,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(10),
            new ThreadPoolExecutor.AbortPolicy());

    abstract protected String getPrex();
    abstract String getOther();

    abstract String getCharSetName();
    @Override
    public String execOrigin(String cmd) {
        ProcessBuilder builder = new ProcessBuilder();
        builder.command(getPrex(),getOther(),cmd);
        return doExec(builder,cmd);
    }



    @Override
    public String execOrigin(String cmd, String dir) {
        ProcessBuilder builder = new ProcessBuilder();
        builder.directory(new File(dir));
        builder.command(getPrex(),getOther(),cmd);
        return  doExec(builder,cmd);
    }

    @Override
    public boolean execHandleResult(String cmd, Function<String, Boolean> function) {
        ProcessBuilder builder = new ProcessBuilder();
        builder.command(getPrex(),getOther(),cmd);
        return doExec(builder,cmd,function);
    }

    @Override
    public boolean execHandleResult(String cmd, String dir, Function<String, Boolean> function) {
        ProcessBuilder builder = new ProcessBuilder();
        builder.directory(new File(dir));
        builder.command(getPrex(),getOther(),cmd);
        return  doExec(builder,cmd,function);
    }

    private String doExec(ProcessBuilder builder,String cmd){
        try {
            Process start = builder.start();
            StreamGobbler streamGobbler = new StreamGobbler(start.getInputStream());
            streamGobbler.setCharset(getCharSetName());
            Future<Object> submit = executor.submit(streamGobbler);
            return (String) submit.get();
        } catch (IOException e) {
            log.error("命令:{}执行失败",cmd,e);
            throw new RuntimeException(e);
        } catch (Exception e){
            log.error("命令:{}执行失败，获取命令执行结果失败",cmd,e);
            throw new RuntimeException(e);
        }
    }

    private boolean doExec(ProcessBuilder builder,String cmd,Function<String,Boolean> function){
        try {
            Process start = builder.start();
            StreamGobbler streamGobbler = new StreamGobbler(start.getInputStream(),function);
            streamGobbler.setCharset(getCharSetName());
            Future<Object> submit = executor.submit(streamGobbler);
            return (boolean) submit.get();
        } catch (IOException e) {
            log.error("命令:{}执行失败",cmd,e);
            throw new RuntimeException(e);
        } catch (Exception e){
            log.error("命令:{}执行失败，获取命令执行结果失败",cmd,e);
            throw new RuntimeException(e);
        }
    }
}
